/*	
 *	This file is part of eduDES.
 *
 *	Copyright 2009 Michael Morckos <mikey.morckos@gmail.com>
 *
 *	eduDES is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation, either version 3 of the License, or
 *	(at your option) any later version.
 *
 *	eduDES is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with eduDES.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "round.h"

unsigned char IP_1[64] = {58, 50, 42, 34, 26, 18, 10, 2, 
                          60, 52, 44, 36, 28, 20, 12, 4, 
                          62, 54, 46, 38, 30, 22, 14, 6, 
                          64, 56, 48, 40 ,32, 24, 16, 8, 
                          57, 49, 41, 33, 25, 17, 9, 1, 
                          59, 51, 43, 35, 27, 19, 11, 3, 
                          61, 53, 45, 37, 29, 21, 13, 5, 
                          63, 55, 47, 39, 31, 23, 15, 7};
                        
unsigned char IP_2[64] = {40, 8, 48, 16, 56, 24, 64, 32, 
                          39, 7, 47, 15, 55, 23, 63, 31, 
                          38, 6, 46, 14, 54, 22, 62, 30, 
                          37, 5, 45, 13, 53, 21, 61, 29, 
                          36, 4, 44, 12, 52, 20, 60, 28, 
                          35, 3, 43, 11, 51, 19, 59, 27, 
                          34, 2, 42, 10, 50, 18, 58, 26, 
                          33, 1, 41, 9, 49, 17, 57, 25};

unsigned char EXPAP[48] = {32, 1, 2, 3, 4, 5, 
                           4, 5, 6, 7, 8, 9, 
                           8, 9, 10, 11, 12, 13, 
                           12, 13, 14, 15, 16, 17, 
                           16, 17, 18, 19, 20, 21, 
                           20, 21, 22, 23, 24, 25, 
                           24, 25, 26, 27, 28, 29, 
                           28, 29, 30, 31, 32, 1};

unsigned char P[32] = {16, 7, 20, 21, 29, 12, 28, 17, 
					   1, 15, 23, 26, 5, 18, 31, 10, 
					   2, 8, 24, 14, 32, 27, 3, 9, 
					   19, 13, 30, 6, 22, 11, 4, 25};
					 

unsigned char SBOX_1 [4][16] = {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
						     	{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
						     	{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
						     	{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}};
						     						   
unsigned char SBOX_2 [4][16] = {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
						     	{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
						     	{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
						     	{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}};
						   
unsigned char SBOX_3 [4][16] = {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
							 	{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
							 	{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
							 	{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}};
						
unsigned char SBOX_4 [4][16] = {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
                             	{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
                             	{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
                             	{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}};
                            
unsigned char SBOX_5 [4][16] = {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
                             	{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
                             	{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
                             	{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}};
                             
unsigned char SBOX_6 [4][16] = {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
							 	{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
							 	{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
							 	{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}};
							 
unsigned char SBOX_7 [4][16] = {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
							 	{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
							 	{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
							 	{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}};

unsigned char SBOX_8 [4][16] = {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
							 	{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
							 	{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
							 	{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}};					 

short _todecimal(unsigned char input[], short len) {
	short i, j, res = 0;
	for(i = len - 1, j = 0; i >= 0; i--, j++)
		res += (pow(2, j) * input[i]);
	return res;
}

unsigned char _tobinary(unsigned char* input) {	
	unsigned char res;
	res = *input % 2;
	*input = *input / 2;
	return res;
}
	
void init_phrase(unsigned char* phrase) {
 	orig_phrase = malloc(sizeof(unsigned char) * 64);
 	curr_phrase = malloc(sizeof(unsigned char) * 64);
 	final_phrase = malloc(sizeof(unsigned char) * 64);
	L_phrase = malloc(sizeof(unsigned char) * 32);
	R_phrase = malloc(sizeof(unsigned char) * 32);
	final_phrase = malloc(sizeof(unsigned char) * 64);
	short i;
	for(i = 0; i < 64; i++)
		orig_phrase[i] = phrase[i];
	applyIP_1();
	free(orig_phrase);
	orig_phrase = 0;		
}

void applyIP_1() {
	short i;
	for(i = 0; i < 64; i++)
		curr_phrase[i] = orig_phrase[IP_1[i] - 1];
}

void splitphrase() {
	short i;
	for(i = 0; i < 32; i++) {
		L_phrase[i] = curr_phrase[i];
		R_phrase[i] = curr_phrase[i + 32];
	}
}

void applyFUNC() {
	short i, j, k;
	short row, col; 
	unsigned char val;
	unsigned char tmp[4];
	R_phrase_tmp = malloc(sizeof(unsigned char) * 32);
	R_phrase_tmp2 = malloc(sizeof(unsigned char) * 32);
	expa_phrase = malloc(sizeof(unsigned char) * 48);
	for(i = 0; i < 48; i++)
		expa_phrase[i] = R_phrase[EXPAP[i] - 1];
	for(i = 0; i < 48; i++) {
		if((expa_phrase[i] == 1 && final_key[i] == 0) || (expa_phrase[i] == 0 && final_key[i] == 1))
			expa_phrase[i] = 1;
		else
			expa_phrase[i] = 0;
	}
	for(i = 0, j = 0; i < 48; i+=6, j+=4) {
		tmp[0] = expa_phrase[i]; 
		tmp[1] = expa_phrase[i+5];
		row = _todecimal(tmp, 2);	
		tmp[0] = expa_phrase[i+1]; 
		tmp[1] = expa_phrase[i+2];
		tmp[2] = expa_phrase[i+3]; 
		tmp[3] = expa_phrase[i+4];
		col = _todecimal(tmp, 4);
		switch((i / 6)) {
			case 0 : val = SBOX_1[row][col]; break;
			case 1 : val = SBOX_2[row][col]; break;
			case 2 : val = SBOX_3[row][col]; break;
			case 3 : val = SBOX_4[row][col]; break;
			case 4 : val = SBOX_5[row][col]; break;
			case 5 : val = SBOX_6[row][col]; break;
			case 6 : val = SBOX_7[row][col]; break;
			case 7 : val = SBOX_8[row][col]; break;
		}	 
		for(k = j + 3; k >= j; k--)
			R_phrase_tmp[k] = _tobinary(&val);
		val = 0;	
	}
	for(i = 0; i < 32; i++)
		R_phrase_tmp2[i] = R_phrase_tmp[P[i] - 1];
	for(i = 0; i < 32; i++) {
		if((R_phrase_tmp2[i] == 1 && L_phrase[i] == 0) || (R_phrase_tmp2[i] == 0 && L_phrase[i] == 1))
			R_phrase_tmp2[i] = 1;
		else
			R_phrase_tmp2[i] = 0;
	}
	for(i = 0; i < 32; i++)
		L_phrase[i] = R_phrase[i];
	for(i = 0; i < 32; i++)
		R_phrase[i] = R_phrase_tmp2[i];
		
	free(R_phrase_tmp2);	
	R_phrase_tmp2 = 0;
	free(R_phrase_tmp);	
	R_phrase_tmp = 0;
	free(expa_phrase);
	expa_phrase = 0;					
}

void finalize_encrypt() {
	short i;
	for(i = 0; i < 32; i++) {
		curr_phrase[i] = R_phrase[i];
		curr_phrase[i + 32] = L_phrase[i];
	}
}

void applyIP_2() {	
	short i;
	for(i = 0; i < 64; i++)
		final_phrase[i] = curr_phrase[IP_2[i] - 1];	
}

void closeround() {
	free(curr_phrase);
	curr_phrase = 0;
	free(L_phrase);
	L_phrase = 0;
	free(R_phrase);
	R_phrase = 0;
	free(final_phrase);
	final_phrase = 0;
}

